[SVM] Inject a "fake" interrupt if we delay an interrupt for an exception
authorTim Deegan <Tim.Deegan@xensource.com>
Wed, 28 Mar 2007 15:02:54 +0000 (15:02 +0000)
committerTim Deegan <Tim.Deegan@xensource.com>
Wed, 28 Mar 2007 15:02:54 +0000 (15:02 +0000)
(instead of just waiting for the next vmexit to inject the pending
interrupt, since that could be some arbitrary number of instructions later).

Signed-off-by: Tim Deegan <Tim.Deegan@xensource.com>
xen/arch/x86/hvm/svm/intr.c

index 89f3f3091257a310838cf3a21cc904f495642f66..0730586308c748bdfc81e4fbe0b75319c45011c9 100644 (file)
@@ -67,20 +67,6 @@ asmlinkage void svm_intr_assist(void)
     int intr_type = APIC_DM_EXTINT;
     int intr_vector = -1;
 
-    /*
-     * Do not deliver a virtual interrupt (vintr) if an exception is pending.
-     * This is because the delivery of the exception can arbitrarily delay
-     * the injection of the vintr (for example, if the exception is handled
-     * via an interrupt gate, hence zeroing RFLAGS.IF). In the meantime the
-     * vTPR can be modified upwards and we can end up delivering the vintr
-     * when it is not in fact valid to do so (because we do not re-check the
-     * vTPR value). Moreover, the guest will be able to see the updated
-     * APIC/PIC state (as if the interrupt had been acknowledged) yet will not
-     * have actually received the interrupt. This could confuse the guest!
-     */
-    if ( vmcb->eventinj.fields.v )
-        return;
-
     /*
      * Previous Interrupt delivery caused this intercept?
      * This will happen if the injection is latched by the processor (hence
@@ -115,11 +101,23 @@ asmlinkage void svm_intr_assist(void)
         return;
 
     /*
-     * Create a 'fake' virtual interrupt on to intercept as soon as the
-     * guest _can_ take interrupts.  Do not obtain the next interrupt from
-     * the vlapic/pic if unable to inject.
+     * If the guest can't take an interrupt right now, create a 'fake'
+     * virtual interrupt on to intercept as soon as the guest _can_ take
+     * interrupts.  Do not obtain the next interrupt from the vlapic/pic
+     * if unable to inject.
+     *
+     * Also do this if there is an exception pending.  This is because
+     * the delivery of the exception can arbitrarily delay the injection
+     * of the vintr (for example, if the exception is handled via an
+     * interrupt gate, hence zeroing RFLAGS.IF). In the meantime:
+     * - the vTPR could be modified upwards, so we need to wait until the
+     *   exception is delivered before we can safely decide that an
+     *   interrupt is deliverable; and
+     * - the guest might look at the APIC/PIC state, so we ought not to have 
+     *   cleared the interrupt out of the IRR.
      */
-    if ( irq_masked(vmcb->rflags) || vmcb->interrupt_shadow )  
+    if ( irq_masked(vmcb->rflags) || vmcb->interrupt_shadow 
+         || vmcb->eventinj.fields.v )  
     {
         vmcb->general1_intercepts |= GENERAL1_INTERCEPT_VINTR;
         HVMTRACE_2D(INJ_VIRQ, v, 0x0, /*fake=*/ 1);